﻿/*
** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
** Digital Equipment Corporation, Maynard, Mass.
** Copyright (c) 1998 Microsoft.
** To anyone who acknowledges that this file is provided "AS IS"
** without any express or implied warranty: permission to use, copy,
** modify, and distribute this file for any purpose is hereby
** granted without fee, provided that the above copyright notices and
** this notice appears in all source code copies, and that none of
** the names of Open Software Foundation, Inc., Hewlett-Packard
** Company, Microsoft, or Digital Equipment Corporation be used in
** advertising or publicity pertaining to distribution of the software
** without specific, written prior permission. Neither Open Software
** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
** Equipment Corporation makes any representations about the
** suitability of this software for any purpose.
*/
#ifndef __GDK_UUID_H__
#define __GDK_UUID_H__


#include <gdk/core/Types.h>
#include <gdk/core/Stream.h>
#include <gdk/core/Property.h>
#include <gdk/core/String.h>


namespace gdk {


#define UUID_STRING_LENGTH	36
#define UUID_NULL			gdk::Uuid()

#define UUID_NODE_STRING_LENGTH	12
#define UUID_NODE_NULL			gdk::uuid_node_t()


#if defined(_WIN32)
#	pragma pack(push,1)
#endif

struct uuid_node_t {
	uint8_t data[6];

public:
	__INLINE__ uuid_node_t(void) {
		((int16_t*)this)[0] = 0;
		((int16_t*)this)[1] = 0;
		((int16_t*)this)[2] = 0;
	}
	__INLINE__ explicit uuid_node_t(const Char buf[UUID_NODE_STRING_LENGTH + 1]) {
		convertFromString(buf);
	}
	__INLINE__ explicit uuid_node_t(const String &str) {
		convertFromString(str);
	}

	__INLINE__ void zero(void) {
		((int32_t*)this)[0] = 0;
		((int16_t*)this)[2] = 0;
	}
	__INLINE__ bool isZero(void) const {
		return(((const int32_t*)this)[0] == 0
			&& ((const int16_t*)this)[2] == 0);
	}

	GDK_CORE_EXPORT bool convertToString(Char buf[UUID_NODE_STRING_LENGTH + 1]) const;
	GDK_CORE_EXPORT bool convertFromString(Char const buf[UUID_NODE_STRING_LENGTH + 1]);

	GDK_CORE_EXPORT String convertToString(void) const;
	GDK_CORE_EXPORT bool   convertFromString(const String &str);

	GDK_CORE_EXPORT int compare(uuid_node_t const &r) const;

	__INLINE__ bool operator ==(uuid_node_t const &r) const { return (compare(r) == 0); }
	__INLINE__ bool operator !=(uuid_node_t const &r) const { return !(*this == r); }
	__INLINE__ bool operator < (uuid_node_t const &r) const { return (compare(r) < 0); }
	__INLINE__ bool operator > (uuid_node_t const &r) const { return (compare(r) > 0); }
	__INLINE__ bool operator <=(uuid_node_t const &r) const { return !(*this > r); }
	__INLINE__ bool operator >=(uuid_node_t const &r) const { return !(*this < r); }

}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
__attribute__((packed))
#endif
;

struct Uuid {
    uint32_t     time_low;
    uint16_t     time_mid;
    uint16_t     time_hi_and_version;
    uint8_t      clock_seq_hi_and_reserved;
    uint8_t      clock_seq_low;
	uuid_node_t  node;

public:
	static Uuid create(void);

	Uuid(void);
	explicit Uuid(const Char buf[UUID_STRING_LENGTH + 1]);
	explicit Uuid(const String &str);

	void zero(void);
	bool isZero(void) const;

	bool   convertToString(Char buf[UUID_STRING_LENGTH + 1]) const;
	bool   convertFromString(Char const buf[UUID_STRING_LENGTH + 1]);

	GDK_CORE_EXPORT String convertToString(void) const;
	bool   convertFromString(String const &str);

	int compare(Uuid const &l) const;

	__INLINE__ bool operator < (Uuid const &r) const { return (compare(r) < 0); }
	__INLINE__ bool operator > (Uuid const &r) const { return (compare(r) > 0); }
	__INLINE__ bool operator <=(Uuid const &r) const { return !(*this > r); }
	__INLINE__ bool operator >=(Uuid const &r) const { return !(*this < r); }
	__INLINE__ bool operator ==(Uuid const &r) const {
		return	( ((int32_t const*)this)[0] == ((int32_t const*)&r)[0] )
			&&	( ((int32_t const*)this)[1] == ((int32_t const*)&r)[1] )
			&&	( ((int32_t const*)this)[2] == ((int32_t const*)&r)[2] )
			&&	( ((int32_t const*)this)[3] == ((int32_t const*)&r)[3] );
	}
	__INLINE__ bool operator !=(Uuid const &r) const { return !(*this == r); }
}
#if defined(__GNUC__) || defined(__IOS__) || defined(__ANDROID__)
__attribute__((packed))
#endif
;

#if defined(_WIN32)
#	pragma pack(pop)
#endif


__INLINE__ void uuid_zero(Uuid &uuid)
{
	((int32_t*)&uuid)[0] = 0;
	((int32_t*)&uuid)[1] = 0;
	((int32_t*)&uuid)[2] = 0;
	((int32_t*)&uuid)[3] = 0;
}

__INLINE__ bool uuid_isZero(const Uuid& uuid)
{
	return	((const int32_t*)&uuid)[0] == 0
		&&	((const int32_t*)&uuid)[1] == 0
		&&	((const int32_t*)&uuid)[2] == 0
		&&	((const int32_t*)&uuid)[3] == 0;
}


/* uuid_create -- generate a UUID */
GDK_CORE_EXPORT int uuid_create(Uuid &uuid);
__INLINE__ Uuid uuid_create(void)
{
	Uuid id;
	uuid_create(id);
	return id;
}

/* uuid_create_md5_from_name -- create a version 3 (MD5) UUID using a
   "name" from a "name space" */
GDK_CORE_EXPORT void uuid_create_md5_from_name(
    Uuid &uuid,         /* resulting UUID */
    const Uuid& nsid,   /* UUID of the namespace */
    const void *name,   /* the name from which to generate a UUID */
    int namelen         /* the length of the name */
);

#if 0
/* uuid_create_sha1_from_name -- create a version 5 (SHA-1) UUID
   using a "name" from a "name space" */
GDK_CORE_EXPORT void uuid_create_sha1_from_name(
    Uuid *uuid,           /* resulting UUID */
    const Uuid& nsid,     /* UUID of the namespace */
    const void *name,     /* the name from which to generate a UUID */
    int namelen           /* the length of the name */
);
#endif

/* uuid_compare --  Compare two UUID's "lexically" and return
        -1   u1 is lexically before u2
         0   u1 is equal to u2
         1   u1 is lexically after u2
   Note that lexical ordering is not temporal ordering!
*/
GDK_CORE_EXPORT int uuid_compare(Uuid const &u1, Uuid const &u2);

//00000000-0000-0000-0000-000000000000
GDK_CORE_EXPORT bool uuid_convertToString(Uuid const &id,Char buf[UUID_STRING_LENGTH+1]);
GDK_CORE_EXPORT bool uuid_convertFromString(Uuid &id,Char const buf[UUID_STRING_LENGTH+1]);

GDK_CORE_EXPORT String uuid_convertToString(Uuid const &id);
GDK_CORE_EXPORT Uuid   uuid_convertFromString(String const &str);

__INLINE__ Uuid::Uuid(void) {
	((int32_t*)this)[0] = 0;
	((int32_t*)this)[1] = 0;
	((int16_t*)this)[4] = 0;
}
__INLINE__ Uuid::Uuid(const Char buf[UUID_STRING_LENGTH+1]) { convertFromString(buf); }
__INLINE__ Uuid::Uuid(const String &str) { convertFromString(str); }
__INLINE__ Uuid Uuid::create(void) { Uuid id; uuid_create(id); return id; }
__INLINE__ void Uuid::zero(void) { return uuid_zero(*this); }
__INLINE__ bool Uuid::isZero(void) const { return uuid_isZero(*this); }
__INLINE__ bool Uuid::convertToString(Char buf[UUID_STRING_LENGTH + 1]) const { return uuid_convertToString(*this, buf); }
__INLINE__ bool Uuid::convertFromString(Char const buf[UUID_STRING_LENGTH + 1]) { return uuid_convertFromString(*this, buf); }
__INLINE__ bool Uuid::convertFromString(String const &text) {
						if (text.getLength() == UUID_STRING_LENGTH)
						{
							return uuid_convertFromString(*this, text);
						}
						zero();
						return false;
					}
__INLINE__ int  Uuid::compare(Uuid const &l) const { return uuid_compare(*this, l); }


template<typename TyIs>
__INLINE__ TyIs& operator >>(TyIs &is, Uuid &i) __THROW1
{
	if (sizeof(Uuid) != is.read(&i, sizeof(Uuid)))
	{
		__THROW__(__TEXT__("Uuid::operator >>"));
	}

	i.time_low = ntoh(i.time_low);
	i.time_mid = ntoh(i.time_mid);
	i.time_hi_and_version = ntoh(i.time_hi_and_version);

	return is;
}

template<typename TyOs>
__INLINE__ TyOs& operator <<(TyOs &os, Uuid const &i) __THROW1
{
	Uuid o = i;
	o.time_low = hton(o.time_low);
	o.time_mid = hton(o.time_mid);
	o.time_hi_and_version = hton(o.time_hi_and_version);

	if (sizeof(Uuid) != os.write(&o, sizeof(Uuid)))
	{
		__THROW__(__TEXT__("Uuid::operator <<"));
	}

	return os;
}


//----------------------------------------------------------------------
__INLINE__ void convertPropertyToClass(const JsonValue &json, Uuid &id) __THROW1
{
	if (!json.isString() || !id.convertFromString(json.asString()))
	{
		__THROW__(__TEXT__("void convertPropertyToClass(JsonValue const &, Uuid &)"));
	}
}
__INLINE__ void convertPropertyToJson(const Uuid &id, JsonValue &json) __THROW1
{
	json = id.convertToString();
}


//----------------------------------------------------------------------
#ifdef __LITTLE_ENDIAN__

	__INLINE__ Uuid hton(Uuid i)
	{
		i.time_low = hton(i.time_low);
		i.time_mid = hton(i.time_mid);
		i.time_hi_and_version = hton(i.time_hi_and_version);
		return i;
	}
	__INLINE__ Uuid ntoh(Uuid i)
	{
		i.time_low = ntoh(i.time_low);
		i.time_mid = ntoh(i.time_mid);
		i.time_hi_and_version = ntoh(i.time_hi_and_version);
		return i;
	}

#else //__BIG_ENDIAN__

	__INLINE__ Uuid hton(Uuid i)
	{
		return i;
	}
	__INLINE__ Uuid ntoh(Uuid i)
	{
		return i;
	}

#endif


/////////////////////////////////////////////////////////////////////////////
__INLINE__ bool        uuid_node_convertToString(uuid_node_t const &node,Char buf[UUID_NODE_STRING_LENGTH+1]) { return node.convertToString(buf); }
__INLINE__ bool        uuid_node_convertFromString(uuid_node_t &node,Char const buf[UUID_NODE_STRING_LENGTH+1]) { return node.convertFromString(buf); }
__INLINE__ String      uuid_node_convertToString(uuid_node_t const &node) { return node.convertToString(); }
__INLINE__ uuid_node_t uuid_node_convertFromString(String const &str) { uuid_node_t node; node.convertFromString(str); return node; }
__INLINE__ int         uuid_node_compare(uuid_node_t const &l,uuid_node_t const &r) { return l.compare(r); }
__INLINE__ bool        uuid_node_isZero(const uuid_node_t& node) { return node.isZero(); }


__INLINE__ void convertPropertyToClass(const JsonValue &json, uuid_node_t &node) __THROW1
{
	if (!json.isString() || !node.convertFromString(json.asString()))
	{
		__THROW__(__TEXT__("void convertPropertyToClass(const JsonValue &, uuid_node_t &)"));
	}
}
__INLINE__ void convertPropertyToJson(const uuid_node_t &node, JsonValue &json) __THROW1
{
	json = node.convertToString();
}

template<typename TyIs>
__INLINE__ TyIs& operator >>(TyIs &is, uuid_node_t &node) __THROW1
{
	if (sizeof(uuid_node_t) != is.read(&node, sizeof(uuid_node_t)))
	{
		__THROW__(__TEXT__("uuid_node_t::operator >>"));
	}
	return is;
}

template<typename TyOs>
__INLINE__ TyOs& operator <<(TyOs &os, uuid_node_t const &node) __THROW1
{
	if (sizeof(uuid_node_t) != os.write(&node, sizeof(uuid_node_t)))
	{
		__THROW__(__TEXT__("uuid_node_t::operator <<"));
	}
	return os;
}



} //gdk


#endif //__GDK_UUID_H__
